/*
 * TimedReport.java
 *
 * Created on October 19, 2007, 2:22 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package assistedpostagger;

import org.apache.xerces.parsers.DOMParser;
import org.apache.xml.serialize.*;
import org.w3c.dom.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

/**
 *
 * @author parezina
 */
public class XMLTimedReport extends Report{
    
    private ArrayList<TimedWord> reportWords;
    private ListIterator<TimedWord> ITReport;
    private Document reportDocument;
    
    /** Creates a new instance of Report */
    public XMLTimedReport() {
        
        reportWords = new ArrayList();
        reportSentences = new ArrayList();
        totalEditableWords = 0;
        reportTime = new TimeInterval();
        reportTime.startNow();
        reportAssisted = false;
        reportDocument = null;
        
    }
    
    protected int getWordIndex() {
        
        int i = ITReport.previousIndex();
        return i;
        
    }
    
    public int getWordPosition() {
        
        ListIterator<TimedWord> tempIT = reportWords.listIterator(ITReport.nextIndex());
        int position = 0;
        
        while(tempIT.hasPrevious()) {
            Word tempWord = tempIT.previous();
            if (tempWord.isEditable())
                position++;
        }
        
        return position;
        
    }
    
    public Word nextWord() {
        
        if (ITReport.hasPrevious()) {
            ITReport.previous();
            TimedWord thisWord = ITReport.next();
            thisWord.stopTimer();
            ITReport.set(thisWord);
        }
        
        TimedWord tempWord = ITReport.next();
        while (!(tempWord.isEditable())) {
            
            tempWord = ITReport.next();
            
        }
        
        tempWord.startTimer();
        ITReport.set(tempWord);
        return tempWord;
        
    }
    
    public Word currentWord() {
        
        int i = this.getWordIndex();
        Word w = reportWords.get(i);
        return w;
        
    }
    
    
    public Word previousWord() {
        
        TimedWord thisWord = ITReport.previous();
        thisWord.stopTimer();
        ITReport.set(thisWord);
        
        TimedWord tempWord = ITReport.previous();
        while (ITReport.hasPrevious() && !(tempWord.isEditable()))
            tempWord = ITReport.previous();
        
        tempWord.startTimer();
        ITReport.set(tempWord);
        
        Word testWord = ITReport.next();
        while (!(testWord.isEditable()))
            testWord = ITReport.next();
        
        return tempWord;
        
    }
    

    public boolean isEndReport() {
        
        ListIterator<TimedWord> tempIT = reportWords.listIterator(ITReport.previousIndex());
        
        Word tempWord = tempIT.next();
        
        while (tempIT.hasNext() && !(tempWord.isEditable()))
            tempWord = tempIT.next();
        boolean hasNext = tempIT.hasNext();
        return !(hasNext);
        
    }
    
    public boolean isBeginningReport() {
        
        ListIterator<TimedWord> tempIT = reportWords.listIterator(ITReport.nextIndex());
        
        if (tempIT.hasPrevious()) {
            tempIT.previous();
            return !(tempIT.hasPrevious());
        } else {
            return true;
        }
        
    }
    
    
    public void setWordIndex(int currentWord) {
        
        TimedWord tempWord;
        TimedWord thisWord = ITReport.previous();
        thisWord.stopTimer();
        tempWord = thisWord;
        ITReport.set(thisWord);
        
        ITReport = reportWords.listIterator();
        
        if (currentWord > totalEditableWords)
            currentWord = totalEditableWords;
        
        while (currentWord > 0) {
            
            tempWord = ITReport.next();
            if (tempWord.isEditable())
                currentWord--;
            
        }
        
        tempWord.startTimer();
        ITReport.set(tempWord);
        
    }

    public int getReportSize() {
        return totalEditableWords;
    }
    
    public int getReportSentenceCount() {
        return reportSentences.size();
    }
    
    public boolean isAnyReportUnknowns() {
        
        boolean isUnknown = false;
        
        ListIterator<TimedWord> tempIT = this.reportWords.listIterator();
        
        while (tempIT.hasNext()) {
            
            Word tempWord = tempIT.next();
            if (tempWord.getPOS().equalsIgnoreCase("??")) {
                isUnknown = true;
            }
        }
        
        return isUnknown;
        
    }
    
    public void tagReportUnknown(ArrayList<String> validTags) {
        
        ListIterator<TimedWord> tempIT = this.reportWords.listIterator();
        
        while (tempIT.hasNext()) {
            
            TimedWord tempWord = tempIT.next();
            if (validTags.contains(tempWord.getPOS())) {
                tempWord.setPOS("??");
                tempIT.set(tempWord);
            }
        }
        
        
    }
        
    
    public void open(File infile, ArrayList<String> validTags) throws IOException {
        
        
        //BufferedReader bfr = new BufferedReader(new FileReader(infile));
        String fileLine, wordPart, tagPart;
        String lastPOS = "STA";
        String sentenceTemp = new String();
        boolean isWordTag;
        String tagTokens[];
        String thisToken[];
        TimedWord thisWord;
        int sentenceCount = 0;
        int wordInSentenceCount = 0;
        totalEditableWords = 0;
        
        
        ArrayList<Integer> sentenceStarters = new ArrayList<Integer>();
        ArrayList<Integer> words = new ArrayList<Integer>();
        
        DOMParser p = new DOMParser();
        try {
        	p.parse(infile.getName());
        } catch (org.xml.sax.SAXException se){
        	return;
        }
       
        reportDocument = p.getDocument();
        reportWords.clear();
        reportSentences.clear();
        reportAssisted = false;
        
        Element eReport = p.getDocument().getDocumentElement();
        
        NodeList nlAnnotNodes = eReport.getElementsByTagName("Annotation");
        NodeList nlTextNode = eReport.getElementsByTagName("TextWithNodes");
        
        if ((nlAnnotNodes != null) && (nlAnnotNodes.getLength() > 0)) {
        	for (int i = 0; i < nlAnnotNodes.getLength(); i++) {
        		
        		Element eAnnotElem = (Element) nlAnnotNodes.item(i);
        		NamedNodeMap nnmAnnotNode = eAnnotElem.getAttributes();
        		Node nType = nnmAnnotNode.getNamedItem("Type");
        		String nodeType = nType.getNodeValue();
        		
        		if (nodeType.equalsIgnoreCase("Sentence")) {
        			Node nStart = nnmAnnotNode.getNamedItem("StartNode");
        			String nodeStart = nStart.getNodeValue();
        			Integer iNodeStart = Integer.valueOf(nodeStart);
        			
        			sentenceStarters.add(iNodeStart);
        			
        		}
        		
        		if (nodeType.equalsIgnoreCase("Token")) {
        			Node nStart = nnmAnnotNode.getNamedItem("StartNode");
        			String nodeStart = nStart.getNodeValue();
        			Integer iNodeStart = Integer.valueOf(nodeStart);
        			
        			NodeList nlFeatures = eAnnotElem.getElementsByTagName("Feature");
        			for (int j = 0; j < nlFeatures.getLength(); j++) {
        				
        				Element eFeatureElem = (Element) nlFeatures.item(j);
        				
        				Node nFeatureName = eFeatureElem.getElementsByTagName("Name").item(0);
        				Node nFeatureValue = eFeatureElem.getElementsByTagName("Value").item(0);
        				
        				String featureName = nFeatureName.getTextContent();
        				if (featureName.equalsIgnoreCase("kind")) {
        					String featureValue = nFeatureValue.getTextContent();
        					if (	featureValue.equalsIgnoreCase("word") ||
        							featureValue.equalsIgnoreCase("number") ) {
        						
        						words.add(iNodeStart);        						
        					}
        				}        				
        			}
        		}
        	}
        }
        
        if ((nlTextNode != null) && (nlTextNode.getLength() > 0)) {
        	for (int i = 0; i < nlTextNode.getLength(); i++) {
        		
        		Node nReportText = nlTextNode.item(i);
            	NodeList nlReportNodes = nReportText.getChildNodes();
        		Integer iLastNode = new Integer(0);
        		
        		for (int j = 0; j < nlReportNodes.getLength(); j++) {
        			        			        			
        			Node nReportNode = nlReportNodes.item(j);	
        			String strNodeName = nReportNode.getNodeName();
        			short nodeType = nReportNode.getNodeType();
        			
        			if (strNodeName.equalsIgnoreCase("Node")) {
        				
        				String nodeNum = 
        					nReportNode.getAttributes().getNamedItem("id").getNodeValue();
        				iLastNode = Integer.valueOf(nodeNum);
        				
        			} else if (nodeType == Node.TEXT_NODE) {
        				
        				String nodeText = nReportNode.getNodeValue();
        				
        				if (sentenceStarters.contains(iLastNode)) {
        					
        					lastPOS = "STA";
        					if (wordInSentenceCount > 0) {
        						reportSentences.add(sentenceTemp);
        						sentenceCount++;
        					}
        					
        					sentenceTemp = new String();
        					wordInSentenceCount = 0;
        					
        				}
        				
        				sentenceTemp = sentenceTemp.concat(nodeText);
        				
        				thisWord = new TimedWord();
        				thisWord.setText(nodeText);
        				thisWord.setPOS("??");
        				thisWord.setSentence(sentenceCount);
        				if (words.contains(iLastNode)) {
        					
        					thisWord.setAssocToken(iLastNode);
        					thisWord.setPrevPOS(lastPOS);
        					thisWord.setEditable(true);
        					thisWord.setPositionInSentence(wordInSentenceCount);
        					wordInSentenceCount++;
                            totalEditableWords++;
                            lastPOS = "??";
        					
        				}
        				
        				reportWords.add(thisWord);
        				        				
        			}
        			
        			/* String strNodeText = nReportNode.getTextContent();
        			String strNodeValue = nReportNode.getNodeValue();
        			String temp = "   "; */
        			
        			
        			
        		}
        		
        		if (wordInSentenceCount > 0) {
    				
    				reportSentences.add(sentenceTemp);
    				sentenceCount++;
    				
    			}
        		/* String strReportText = nReportText.getTextContent();
            	String strNodeName = nReportText.getNodeName();
            	String strTemp = strReportText; */	
        	}
        	
        }
        
        /* if (bfr.ready()) {
            reportWords.clear();
            reportSentences.clear();
            reportAssisted = false;
        } */
        
              
        
        /* while(bfr.ready()) {
            fileLine = bfr.readLine();
            
            if (fileLine.equalsIgnoreCase("assist")) {
                reportAssisted = true;
            }
            if (fileLine.contains("/")) {
                tagTokens = fileLine.split("\\s");
                lastPOS = "STA";
                String sentenceTemp = new String();
                wordInSentenceCount = 0;
                for (int i = 0; i < tagTokens.length; i++) {
                    if (tagTokens[i].contains("/")) {
                        thisToken = tagTokens[i].split("/");
                        wordPart = thisToken[0];
                        tagPart = thisToken[1];
                        isWordTag = (validTags.contains(tagPart)); // tags have alphanumerics
                        
                        if ((lastPOS == "STA") || !(isWordTag)) {
                            sentenceTemp = sentenceTemp.concat(wordPart);
                        } else {
                            sentenceTemp = sentenceTemp.concat(" " + wordPart);
                        }
                        
                        thisWord = new TimedWord();
                        
                        thisWord.setText(wordPart);
                        thisWord.setPOS(tagPart);
                        thisWord.setSentence(sentenceCount);
                        if (isWordTag) {
                            thisWord.setPrevPOS(lastPOS);
                            thisWord.setEditable(true);
                            thisWord.setPositionInSentence(wordInSentenceCount);
                            wordInSentenceCount++;
                            totalEditableWords++;
                            lastPOS = tagPart;
                        }
                        reportWords.add(thisWord);
                    }
                }
                reportSentences.add(sentenceTemp);
                sentenceCount++;
            }
        } */
        
        ITReport = reportWords.listIterator();
        reportTime = new TimeInterval();
        reportTime.startNow();
        
        //bfr.close();
        
    }
    
    public void save(File outfile) throws IOException {
        
        BufferedWriter bfw = new BufferedWriter(new FileWriter(outfile));
        
        
        //String currentLine = "";
        
        Iterator<TimedWord> ITreportSave = reportWords.iterator();
        
        if (ITReport.hasPrevious()) {
            TimedWord tempWord = ITReport.previous();
            tempWord.stopTimer();
            tempWord.startTimer();
            ITReport.set(tempWord);
            ITReport.next();
        }
        
        reportTime.endNow();
        reportTime.computeInterval();
        //bfw.write(reportTime.toString());
        
        XMLSerializer xmlOut = new XMLSerializer();
        
        xmlOut.setOutputCharStream(bfw);
        
        xmlOut.serialize(reportDocument);
        
        /* while (ITreportSave.hasNext()) {
            
            TimedWord thisWord = ITreportSave.next();
            if (thisWord.getPositionInSentence() == 0) {
                if (currentLine != "") {
                    bfw.write(currentLine);
                    bfw.newLine();
                    currentLine = "";
                }
            }
            
            String thisTuple = thisWord.getText() + "/" + thisWord.getPOS() + "/" + thisWord.getSecondsElapsed();
            if (currentLine != "") {
                currentLine = currentLine + " " + thisTuple;
            } else {
                currentLine = thisTuple;
            }
            
        }
        
        if (currentLine != "") {
            bfw.write(currentLine);
        }
        
        */
        
        bfw.close();
        
    }
    
    public String getSentence(int sentenceNum) {
        
        return reportSentences.get(sentenceNum);
        
    }
    
    public int getCurrentSentenceNum() {
        
        ListIterator<TimedWord> tempIT = reportWords.listIterator(ITReport.nextIndex());
        int snum = tempIT.previous().getSentence();
        
        return snum;
    }
    
    public int getTotalWords() {
        
        return this.totalEditableWords;
        
    }
    
    public String getPastCurrentSentence() {
        
        ListIterator<TimedWord> tempIT = reportWords.listIterator(ITReport.nextIndex());
        String outPast = "";
        
        if (!(tempIT.hasPrevious()))
            return outPast;
        
        Word tempWord = tempIT.previous();
        
        while(tempWord.getPositionInSentence() != 0) {
            tempWord = tempIT.previous();
            outPast = tempWord.getText().concat(outPast);
        }
        
        return outPast;
        
    }
    
    public String getRemainderCurrentSentence() {
        
        ListIterator<TimedWord> tempIT = reportWords.listIterator(ITReport.nextIndex());
        String outRest = "";
        
        if (!(tempIT.hasNext()))
            return outRest;
        
        Word tempWord = tempIT.next();
        
        while((tempWord.getPositionInSentence() != 0) && (tempIT.hasNext())) {
            outRest = outRest.concat(tempWord.getText());
            tempWord = tempIT.next();
        }
        if (tempWord.getPositionInSentence() != 0)
            outRest = outRest.concat(tempWord.getText());
        
        return outRest;
        
    }
    
    public String getWordTag() {
        
        return this.currentWord().getPOS();
        
    }
    
    private TimedWord currentTimedWord() {
        
        int i = this.getWordIndex();
        TimedWord w = reportWords.get(i);
        return w;
        
    }
    
    public void updateCurrentTag(String newTag) {
        
        ListIterator<TimedWord> tempIT = reportWords.listIterator(ITReport.nextIndex());
        TimedWord tempWord = this.currentTimedWord();
        tempWord.setPOS(newTag);
        
        Integer wordToken = tempWord.getAssocToken();
        
        this.reportWords.set(this.getWordIndex(), tempWord);
        
        if (tempIT.hasNext()) {
            tempWord = tempIT.next();
            while(tempIT.hasNext() && !(tempWord.isEditable())) {
                tempWord = tempIT.next();
            }
            if (tempWord.isEditable()) {
                if (!(tempWord.getPrevPOS().equalsIgnoreCase("STA"))) {
                    tempWord.setPrevPOS(newTag);
                    this.reportWords.set(tempIT.previousIndex(), tempWord);
                }
            }
        }
        
        Element eReport = reportDocument.getDocumentElement();
        
        NodeList nlAnnotNodes = eReport.getElementsByTagName("Annotation");
        
        if ((nlAnnotNodes != null) && (nlAnnotNodes.getLength() > 0)) {
        	for (int i = 0; i < nlAnnotNodes.getLength(); i++) {
        		
        		Element eAnnotElem = (Element) nlAnnotNodes.item(i);
        		NamedNodeMap nnmAnnotNode = eAnnotElem.getAttributes();
        		Node nType = nnmAnnotNode.getNamedItem("Type");
        		String nodeType = nType.getNodeValue();

        		if (nodeType.equalsIgnoreCase("Token")) {
        			Node nStart = nnmAnnotNode.getNamedItem("StartNode");
        			String nodeStart = nStart.getNodeValue();
        			Integer iNodeStart = Integer.valueOf(nodeStart);
        			
        			if (iNodeStart.compareTo(wordToken) == 0) {
        			
        				NodeList nlFeatures = eAnnotElem.getElementsByTagName("Feature");
        				for (int j = 0; j < nlFeatures.getLength(); j++) {
        				
        					Element eFeatureElem = (Element) nlFeatures.item(j);
        				
        					Node nFeatureName = eFeatureElem.getElementsByTagName("Name").item(0);
        					Node nFeatureValue = eFeatureElem.getElementsByTagName("Value").item(0);
        				
        					String featureName = nFeatureName.getTextContent();
        					if (featureName.equalsIgnoreCase("category")) {

        						NodeList nlFeatureText = nFeatureValue.getChildNodes();
        						
        						for (int k = 0; k < nlFeatureText.getLength(); k++) {
        							
        							Node nFeatureChild = nlFeatureText.item(k);
        							if (nFeatureChild.getNodeType() == Node.TEXT_NODE) {
        								
        								nFeatureChild.setNodeValue(newTag);
        								
        							}
        							
        						}
        						
        					}        				
        				}
        			}
        		}
        	}
        }
        
    }

    public boolean isReportAssisted() {
        return reportAssisted;
    }

    public void setReportAssisted(boolean reportAssisted) {
        this.reportAssisted = reportAssisted;
    }
    
    
}
    
    